home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 3 / BBS in a box - Trilogy III.iso / Files / System7 tools / Frontier / Frontier SDK 2.1 / Sample Code / BarChart / barchart.c next >
Encoding:
C/C++ Source or Header  |  1993-06-09  |  26.1 KB  |  1,302 lines  |  [TEXT/KAHL]

  1.  
  2.  
  3.  
  4. /*© Copyright 1988-1992 UserLand Software, Inc.  All Rights Reserved.*/
  5.  
  6.  
  7. #include <applet.h>
  8. #include <appletfrontier.h>
  9.  
  10. /*
  11. DW 6/15/92: bring up to date with Applet Toolkit 2.0
  12.  
  13.     1. remove all calls to apppushwindow/apppopwindow. the toolkit now takes
  14.     care of being sure the port is properly set before any applet routines are
  15.     called. no need to do this, and it was screwing up offscreen bitmaps.
  16.     
  17.     2. added color. set app.usecolor in main, use pushforecolor/popforecolor
  18.     in drawing bars and labels, added a clut resource to barchart.π.rsrc. 
  19.     defined labelcolor and firstbarcolor.
  20.     
  21.     3. added support for smart window zooming. see bcgetcontentsize.
  22.     
  23. DW 8/11/92: added two system event handlers. see bcfastiacmessage.
  24.     
  25.     1. There's a table at BarChart.fast with two glue scripts that connect to
  26.     these fast event handlers.
  27.     
  28. DW 8/22/92: implemented a putpicture callback.
  29.  
  30.     1. It allows a script to set the background picture for a barchart window.
  31.     The picture is not saved. 
  32.     
  33.     2. It was implemented as part of documenting the app.putPicture verb, we now
  34.     have pictures flowing two-way from BarChart into the object database.
  35. */
  36.  
  37.  
  38. #define minwindowwidth 100 /*New in 2.0 -- for zooming windows*/
  39.  
  40. #define labelcolor blackindex /*draw labels in black, other colors look flaky*/
  41.  
  42. #define firstbarcolor 8 /*start of a set of bold colors*/
  43.  
  44. #define backgroundcolor 46 /*a soft green color*/
  45.  
  46.  
  47. /*
  48. these are the IAC messages that BarChart can receive from Frontier scripts.
  49.  
  50. for the other side of this interface, check out system.verbs.apps.BarChart in
  51. frontier.root.
  52. */
  53.     #define setbarvaluetoken     'sval'
  54.     #define getbarvaluetoken     'gval'
  55.     #define setbarlabeltoken     'slab'
  56.     #define getbarlabeltoken     'glab'
  57.     #define setbartoken            'sbar'
  58.     #define addbartoken         'abar'
  59.     #define setunitstoken        'sunt'
  60.     #define setbarcounttoken    'scnt'
  61.     #define getbarcounttoken    'gcnt'
  62.     #define updatetoken            'updt'
  63.     
  64.  
  65.  
  66. #define maxbars 25
  67.  
  68. typedef long tyvalues [maxbars]; /*holds an array worth of values*/
  69.  
  70. #define maxlabelchars 32
  71.  
  72.  
  73. typedef struct tybarrecord {
  74.     
  75.     boolean flhasbeenset: 1; /*avoid displaying if it's never been assigned to*/
  76.     
  77.     boolean fldirty: 1; /*the bar needs updating, watch for this in the idle callback*/
  78.     
  79.     long value;
  80.     
  81.     char label [maxlabelchars];
  82.     } tybarrecord;
  83.  
  84.  
  85. typedef struct tybarchartrecord {
  86.     
  87.     short versionnumber; /*this structure is saved on disk*/
  88.     
  89.     PicHandle backgroundpicture; /*picture displayed behind bars*/
  90.     
  91.     boolean flactive: 1; /*true if our window is active, false otherwise*/
  92.     
  93.     bigstring barunits; /*concatenated at the end of every displayed value*/
  94.     
  95.     short ctbars; /*number of bars in the chart*/
  96.     
  97.     long minvalue, maxvalue; /*the range of values*/
  98.     
  99.     short pixelsbetweenbars; /*how much space between the bars?*/
  100.     
  101.     short onebarwidth; /*how wide is one of the bars?*/
  102.     
  103.     short maxbarheight; /*max height in pixels of a bar*/
  104.     
  105.     short horizbaseline; /*the bottom edge of all the bars*/
  106.     
  107.     short vertbaseline; /*the left edge of the first bar*/
  108.     
  109.     short labelfont, labelsize, labelstyle; /*how are labels drawn?*/
  110.     
  111.     short labelbaseline; /*the horiz baseline for bar labels*/
  112.     
  113.     short labellineheight; /*vertical pixels for a label*/
  114.     
  115.     tybarrecord bars [maxbars];
  116.     } tybarchartrecord, *ptrbarchartrecord, **hdlbarchartrecord;
  117.     
  118.     
  119. bigstring bsbarchartsearch; /*see selectbarchartwindow*/
  120.  
  121. #define pictmargin 20 /*leave this much room on all sides of chart*/
  122.  
  123.  
  124.  
  125.  
  126. static short getbackgroundcolor (void) {
  127.  
  128.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  129.     
  130.     if ((**hb).flactive)
  131.         return (backgroundcolor);
  132.     else
  133.         return (whiteindex);
  134.     } /*getbackgroundcolor*/
  135.     
  136.  
  137. static void pushlabelstyle (void) {
  138.     
  139.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  140.     
  141.     pushstyle ((**hb).labelfont, (**hb).labelsize, (**hb).labelstyle);
  142.     } /*pushlabelstyle*/
  143.     
  144.     
  145. static boolean setchartconsts (void) {
  146.     
  147.     /*
  148.     set values for the computed and constant fields of the barchart record.
  149.     
  150.     assume non-computed fields have been set and are accurate.
  151.     */
  152.     
  153.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  154.     hdlappwindow ha = app.appwindow;
  155.     short totalwidth;
  156.     short ctbars = (**hb).ctbars;
  157.     Rect r;
  158.     
  159.     (**hb).pixelsbetweenbars = 10;
  160.     
  161.     (**hb).labelfont = geneva;
  162.     
  163.     (**hb).labelsize = 9;
  164.     
  165.     (**hb).labelstyle = bold;
  166.     
  167.     pushlabelstyle ();
  168.     
  169.     (**hb).labellineheight = globalfontinfo.ascent + globalfontinfo.descent;
  170.     
  171.     popstyle ();
  172.     
  173.     r = (**ha).windowrect;
  174.     
  175.     totalwidth = (**ha).windowhorizpixels - (2 * pictmargin);
  176.     
  177.     totalwidth -= (ctbars + 1) * (**hb).pixelsbetweenbars;
  178.     
  179.     if (ctbars <= 0) 
  180.         (**hb).onebarwidth = 0; /*defensive driving*/
  181.     else
  182.         (**hb).onebarwidth = totalwidth / ctbars;
  183.     
  184.     (**hb).labelbaseline = r.bottom - pictmargin;
  185.     
  186.     (**hb).horizbaseline = r.bottom - pictmargin - (2 * (**hb).labellineheight);
  187.     
  188.     (**hb).maxbarheight = (**hb).horizbaseline - r.top - pictmargin;
  189.     
  190.     (**hb).vertbaseline = r.left + pictmargin;
  191.     
  192.     return (true);
  193.     } /*setchartconsts*/
  194.     
  195.     
  196. static short getbarleftedge (short barnum) {
  197.  
  198.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  199.  
  200.     return ( 
  201.         (**hb).vertbaseline + 
  202.         
  203.         ((**hb).pixelsbetweenbars * (barnum + 1)) + 
  204.         
  205.         ((**hb).onebarwidth * barnum));
  206.     } /*getbarleftedge*/
  207.     
  208.  
  209. static boolean drawbar (short barnumber) {
  210.     
  211.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  212.     hdlappwindow ha = app.appwindow;
  213.     short barnum = barnumber;
  214.     short maxbarheight = (**hb).maxbarheight;
  215.     long value = (**hb).bars [barnum].value;
  216.     long maxvalue = (**hb).maxvalue;
  217.     short whitearea;
  218.     Rect rbar, rwindow, rbitmap;
  219.     
  220.     if (!(**hb).bars [barnum].flhasbeenset)
  221.         return (true);
  222.         
  223.     rwindow = (**ha).windowrect;
  224.     
  225.     rbar.left = getbarleftedge (barnum);
  226.         
  227.     rbar.right = rbar.left + (**hb).onebarwidth;
  228.     
  229.     rbar.bottom = (**hb).horizbaseline;
  230.     
  231.     rbar.top = rbar.bottom - maxbarheight;
  232.     
  233.     rbitmap = rbar;
  234.     
  235.     pushforecolor (firstbarcolor + barnumber); /*New in 2.0*/
  236.     
  237.     pushbackcolor (getbackgroundcolor ());
  238.         
  239.     EraseRect (&rbar);
  240.     
  241.     if (maxvalue == 0) /*avoid divide by zero error*/
  242.         whitearea = 0;
  243.         
  244.     else { /*do arithmetic with longs*/
  245.         
  246.         long l1 = maxvalue - value;
  247.         long l2 = maxbarheight;
  248.         long l3 = maxvalue;
  249.         long l4 = (l1 * l2) / l3;
  250.         
  251.         whitearea = (short) l4;
  252.         }
  253.     
  254.     if (whitearea > 0)
  255.         rbar.top += whitearea;
  256.     
  257.     if ((**hb).flactive)
  258.         FillRect (&rbar, quickdrawglobal (gray));
  259.     else 
  260.         FillRect (&rbar, quickdrawglobal (ltGray));        
  261.     
  262.     pushpen ();
  263.     
  264.     PenPat (quickdrawglobal (black));
  265.  
  266.     FrameRect (&rbar);
  267.     
  268.     poppen ();
  269.     
  270.     popbackcolor ();
  271.     
  272.     popforecolor ();
  273.     
  274.     return (true);
  275.     } /*drawbar*/
  276.     
  277.     
  278. static boolean drawlabel (short barnumber) {
  279.     
  280.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  281.     hdlappwindow ha = app.appwindow;
  282.     hdlstring hstring;
  283.     short lh = (**hb).labellineheight;
  284.     bigstring bs;
  285.     Rect r;
  286.     
  287.     if (!(**hb).bars [barnumber].flhasbeenset)
  288.         return (true);
  289.         
  290.     pushclip ((**ha).windowrect);
  291.         
  292.     pushforecolor (labelcolor); /*New in 2.0*/
  293.         
  294.     pushbackcolor (getbackgroundcolor ());
  295.         
  296.     pushlabelstyle ();
  297.     
  298.     r.left = getbarleftedge (barnumber);
  299.         
  300.     r.right = r.left + (**hb).onebarwidth;
  301.     
  302.     r.bottom = (**hb).labelbaseline - lh;
  303.     
  304.     r.top = r.bottom - lh;
  305.     
  306.     copystring ((**hb).bars [barnumber].label, bs);
  307.     
  308.     EraseRect (&r);
  309.     
  310.     centerstring (r, bs);
  311.     
  312.     r.bottom += lh;
  313.     
  314.     r.top += lh;
  315.     
  316.     NumToString ((**hb).bars [barnumber].value, bs);
  317.     
  318.     pushstring ((**hb).barunits, bs);
  319.         
  320.     EraseRect (&r);
  321.     
  322.     centerstring (r, bs);
  323.     
  324.     popstyle ();
  325.     
  326.     popbackcolor ();
  327.     
  328.     popforecolor ();
  329.     
  330.     popclip ();
  331.     
  332.     return (true);
  333.     } /*drawlabel*/
  334.     
  335.     
  336. static void drawbarchart (void) {
  337.     
  338.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  339.     short i;
  340.     
  341.     for (i = 0; i < (**hb).ctbars; i++) {
  342.         
  343.         drawbar (i);
  344.         
  345.         drawlabel (i);
  346.         } /*for*/
  347.     } /*drawbarchart*/
  348.     
  349.  
  350. static void drawfreemem (void) {
  351.     
  352.     Rect r;
  353.     Str255 s;
  354.     
  355.     r = (*thePort).portRect;
  356.     
  357.     r.top = r.bottom - 15;
  358.     
  359.     r.right -= 20;
  360.     
  361.     EraseRect (&r);
  362.     
  363.     NumToString (FreeMem () / 1024, s);
  364.     
  365.     MoveTo (r.left + 3, r.bottom - 3);
  366.     
  367.     setfontsizestyle (geneva, 9, 0);
  368.     
  369.     DrawString (s);
  370.     
  371.     DrawString ("\pK");
  372.     } /*drawfreemem*/
  373.     
  374.     
  375. static boolean setminmax (void) {
  376.     
  377.     /*
  378.     examine the values array, and reset the min and max, if necessary.
  379.     
  380.     return true if at least one changed, false otherwise.
  381.     */
  382.     
  383.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  384.     long newmax, newmin;
  385.     long val;
  386.     short i;
  387.     
  388.     newmax = intminusinfinity; /*assume only short values*/
  389.     
  390.     for (i = 0; i < (**hb).ctbars; i++) {
  391.         
  392.         val = (**hb).bars [i].value;
  393.         
  394.         if (val > newmax)
  395.             newmax = val;
  396.         } /*for*/
  397.             
  398.     newmin = intinfinity; /*assume only short values*/
  399.     
  400.     for (i = 0; i < (**hb).ctbars; i++) {
  401.         
  402.         val = (**hb).bars [i].value;
  403.         
  404.         if (val < newmin)
  405.             newmin = val;
  406.         } /*for*/
  407.             
  408.     if ((newmax != (**hb).maxvalue) || (newmin != (**hb).minvalue)) {
  409.         
  410.         (**hb).maxvalue = newmax;
  411.         
  412.         (**hb).minvalue = newmin;
  413.         
  414.         return (true);
  415.         }
  416.     
  417.     return (false); /*no change*/
  418.     } /*setminmax*/
  419.     
  420.     
  421. static void smashchartdisplay (boolean flerase) {
  422.  
  423.     hdlappwindow ha = app.appwindow;
  424.     Rect r;
  425.  
  426.     setchartconsts (); /*reset all the drawing parameters*/
  427.     
  428.     setminmax (); /*min and max might have changed*/
  429.     
  430.     invalappwindow (ha, flerase);
  431.     
  432.     updateappwindow (ha);
  433.     } /*smashchartdisplay*/
  434.     
  435.  
  436. static boolean setbarunits (bigstring bs) {
  437.     
  438.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  439.  
  440.     copystring (bs, (**hb).barunits);
  441.     
  442.     smashchartdisplay (false); /*redraw the whole thing*/
  443.     
  444.     (**app.appwindow).flmadechanges = true;
  445.     
  446.     return (true);
  447.     } /*setbarunits*/
  448.     
  449.     
  450. static boolean setbarvalue (short barnumber, long barvalue) {
  451.     
  452.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  453.  
  454.     if ((barnumber < 0) || (barnumber >= (**hb).ctbars)) /*defensive driving*/
  455.         return (false);
  456.     
  457.     (**hb).bars [barnumber].value = barvalue;
  458.     
  459.     (**hb).bars [barnumber].flhasbeenset = true;
  460.     
  461.     if (setminmax ())
  462.         smashchartdisplay (false); /*redraw the whole thing*/
  463.         
  464.     else {
  465.         drawbar (barnumber);
  466.     
  467.         drawlabel (barnumber);
  468.         }
  469.     
  470.     (**app.appwindow).flmadechanges = true;
  471.  
  472.     return (true);
  473.     } /*setbarvalue*/
  474.     
  475.  
  476. static boolean getbarvalue (short barnumber, long *barvalue) {
  477.     
  478.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  479.  
  480.     *barvalue = 0; /*default returned value*/
  481.     
  482.     if ((barnumber < 0) || (barnumber >= (**hb).ctbars)) /*defensive driving*/
  483.         return (false);
  484.     
  485.     *barvalue = (**hb).bars [barnumber].value;
  486.     
  487.     return (true);
  488.     } /*getbarvalue*/
  489.     
  490.     
  491. static boolean setallvalues (short ct, tyvalues vals) {
  492.     
  493.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  494.     short i;
  495.     
  496.     for (i = 0; i < ct; i++) {
  497.     
  498.         (**hb).bars [i].value = vals [i];
  499.         
  500.         (**hb).bars [i].flhasbeenset = true;
  501.         } /*for*/
  502.         
  503.     setminmax ();
  504.     
  505.     smashchartdisplay (false); /*redraw the whole thing*/
  506.     
  507.     (**app.appwindow).flmadechanges = true;
  508.  
  509.     return (true);
  510.     } /*setallvalues*/
  511.     
  512.     
  513. static boolean setbarlabel (short barnumber, bigstring bslabel) {
  514.     
  515.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  516.     
  517.     if ((barnumber < 0) || (barnumber >= (**hb).ctbars)) /*defensive driving*/
  518.         return (false);
  519.         
  520.     copystring (bslabel, (**hb).bars [barnumber].label);
  521.     
  522.     (**hb).bars [barnumber].flhasbeenset = true;
  523.     
  524.     drawlabel (barnumber);
  525.     
  526.     (**app.appwindow).flmadechanges = true;
  527.     
  528.     return (true);
  529.     } /*setbarlabel*/
  530.     
  531.  
  532. static boolean setbar (short barnumber, bigstring bslabel, long barvalue) {
  533.     
  534.     /*
  535.     sets both the label and the value for the indicated bar.
  536.     
  537.     this is provided so that a single IAC call can set both.
  538.     */
  539.     
  540.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  541.  
  542.     if ((barnumber < 0) || (barnumber >= (**hb).ctbars)) /*defensive driving*/
  543.         return (false);
  544.     
  545.     if (!setbarlabel (barnumber, bslabel))
  546.         return (false);
  547.         
  548.     return (setbarvalue (barnumber, barvalue));
  549.     } /*setbar*/
  550.     
  551.     
  552. static short addbar (bigstring bslabel, long barvalue) {
  553.     
  554.     /*
  555.     returns the number of the new bar, -1 if it failed.
  556.     */
  557.     
  558.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  559.     short barnumber = (**hb).ctbars;
  560.     
  561.     (**hb).ctbars++;
  562.     
  563.     setbarvalue (barnumber, barvalue);
  564.     
  565.     if (!setbarlabel (barnumber, bslabel)) {
  566.         
  567.         (**hb).ctbars--;
  568.         
  569.         return (-1);
  570.         }
  571.     
  572.     smashchartdisplay (true);
  573.     
  574.     (**app.appwindow).flmadechanges = true;
  575.  
  576.     return (barnumber);
  577.     } /*addbar*/
  578.     
  579.  
  580. static boolean getbarlabel (short barnumber, bigstring bslabel) {
  581.     
  582.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  583.     
  584.     setemptystring (bslabel); /*default returned value*/
  585.     
  586.     if ((barnumber < 0) || (barnumber >= (**hb).ctbars)) /*defensive driving*/
  587.         return (false);
  588.     
  589.     copystring ((**hb).bars [barnumber].label, bslabel);
  590.     
  591.     return (true);
  592.     } /*getbarlabel*/
  593.     
  594.  
  595. static boolean resetbarchartwindow (short ctbars) {
  596.     
  597.     (**(hdlbarchartrecord) app.appdata).ctbars = ctbars;
  598.     
  599.     smashchartdisplay (false);
  600.     
  601.     (**app.appwindow).flmadechanges = true;
  602.  
  603.     return (true);
  604.     } /*resetbarchartwindow*/
  605.     
  606.     
  607. static boolean bcnewrecord (void) {
  608.     
  609.     hdlbarchartrecord hb;
  610.     short i;
  611.     
  612.     if (!newclearhandle (longsizeof (tybarchartrecord), (Handle *) &app.appdata))
  613.         return (false);
  614.         
  615.     hb = (hdlbarchartrecord) app.appdata;
  616.     
  617.     (**hb).versionnumber = 1;
  618.     
  619.     (**hb).ctbars = 0;
  620.     
  621.     (**hb).minvalue = 0;
  622.     
  623.     (**hb).maxvalue = 0;
  624.     
  625.     (**hb).pixelsbetweenbars = 10;
  626.     
  627.     for (i = 0; i < maxbars; i++) {
  628.         
  629.         (**hb).bars [i].value = 0;
  630.         
  631.         setstringlength ((**hb).bars [i].label, 0);
  632.         } /*for*/
  633.     
  634.     setchartconsts ();
  635.     
  636.     return (true);
  637.     } /*bcnewrecord*/
  638.  
  639.  
  640. static boolean bcdisposerecord (void) {
  641.     
  642.     disposehandle ((Handle) app.appdata);
  643.         
  644.     return (true);
  645.     } /*bcdisposerecord*/
  646.     
  647.     
  648. static boolean bcadjustcursor (void) {
  649.  
  650.     arrowcursor (); /*BarChart's "adjust cursor" is pretty simple*/
  651.     
  652.     return (true);
  653.     } /*bcadjustcursor*/
  654.  
  655.  
  656. static boolean bcwindowresize (void) {
  657.  
  658.     setchartconsts (); /*reset all computed values*/
  659.     
  660.     return (true);
  661.     } /*bcwindowresize*/
  662.     
  663.  
  664. static boolean bcactivate (boolean flactive) {
  665.     
  666.     /*
  667.     activate or deactivate the indicated BarChart window.  we can't depend
  668.     on the BC globals being properly set because we may be working with a 
  669.     window that's not the frontmost window.
  670.     
  671.     returns true if we consumed the activate.
  672.     */
  673.     
  674.     hdlappwindow ha = app.appwindow;
  675.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  676.     
  677.     if (hb == nil) /*no data, it can't be our window*/
  678.         return (false);
  679.         
  680.     invalappwindow (ha, false);
  681.         
  682.     (**hb).flactive = flactive;
  683.     
  684.     return (true);
  685.     } /*bcactivate*/
  686.     
  687.     
  688. static boolean bcupdate (void) {
  689.     
  690.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  691.     hdlappwindow ha = app.appwindow;
  692.     boolean flbitmap = false;
  693.     Rect rcontent = (**ha).contentrect;
  694.     
  695.     if (hb == nil) /*no data, it can't be our window*/
  696.         return;
  697.         
  698.     flbitmap = appopenbitmap ((**ha).windowrect, ha);
  699.     
  700.     pushbackcolor (getbackgroundcolor ());
  701.     
  702.     EraseRect (&rcontent);
  703.     
  704.     DrawPicture ((**hb).backgroundpicture, &rcontent);
  705.     
  706.     drawfreemem ();
  707.     
  708.     drawbarchart ();
  709.     
  710.     popbackcolor ();
  711.     
  712.     if (flbitmap)
  713.         appclosebitmap (ha);
  714.         
  715.     return (true);
  716.     } /*bcupdate*/
  717.     
  718.     
  719. static void allbarsdirty (void) {
  720.     
  721.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  722.     short i;
  723.     
  724.     for (i = 0; i < (**hb).ctbars; i++) 
  725.         (**hb).bars [i].fldirty = true;
  726.     } /*bcidle*/
  727.     
  728.  
  729. static boolean fastsetbarvalue (short barnumber, long barvalue) {
  730.     
  731.     /*
  732.     called in a system event handler, so it can't actually update the window.
  733.     
  734.     we set things up so that the updating happpens in the idle callback, when
  735.     we're not running in the scripting system context.
  736.     */
  737.     
  738.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  739.  
  740.     if ((barnumber < 0) || (barnumber >= (**hb).ctbars)) /*defensive driving*/
  741.         return (false);
  742.     
  743.     (**hb).bars [barnumber].value = barvalue;
  744.     
  745.     (**hb).bars [barnumber].flhasbeenset = true;
  746.     
  747.     (**hb).bars [barnumber].fldirty = true;
  748.     
  749.     if (setminmax ())
  750.         allbarsdirty (); 
  751.     
  752.     (**app.appwindow).flmadechanges = true;
  753.  
  754.     return (true);
  755.     } /*fastsetbarvalue*/
  756.     
  757.  
  758. static boolean fastsetbarvalueverb (void) {
  759.     
  760.     /*
  761.     verb that sets the value of one of the bars in the target window.
  762.     */
  763.     
  764.     short barnumber;
  765.     long barvalue;
  766.     
  767.     if (!IACgetshortparam (keyDirectObject, &barnumber))
  768.         return (false);
  769.         
  770.     barnumber--; /*our IAC interface is 1-based, internally we're 0-based*/
  771.         
  772.     if (!IACgetlongparam ('vbar', &barvalue))
  773.         return (false);
  774.         
  775.     return (IACreturnboolean (fastsetbarvalue (barnumber, barvalue)));
  776.     } /*fastsetbarvalueverb*/
  777.     
  778.  
  779. static boolean fastgetbarvalueverb (void) {
  780.     
  781.     /*
  782.     verb that returns the value of one of the bars in the target window.
  783.     */
  784.     
  785.     short barnumber;
  786.     long barvalue;
  787.     
  788.     if (!IACgetshortparam (keyDirectObject, &barnumber))
  789.         return (false);
  790.         
  791.     barnumber--; /*our IAC interface is 1-based, internally we're 0-based*/
  792.         
  793.     getbarvalue (barnumber, &barvalue);
  794.         
  795.     return (IACreturnlong (barvalue));
  796.     } /*fastgetbarvalueverb*/
  797.     
  798.  
  799. static boolean setbarvalueverb (void) {
  800.     
  801.     /*
  802.     verb that sets the value of one of the bars in the target window.
  803.     */
  804.     
  805.     short barnumber;
  806.     long barvalue;
  807.     
  808.     if (!settargetglobals ()) /*this verb requires an open barchart window*/
  809.         return (false);
  810.         
  811.     if (!IACgetshortparam (keyDirectObject, &barnumber))
  812.         return (false);
  813.         
  814.     barnumber--; /*our IAC interface is 1-based, internally we're 0-based*/
  815.         
  816.     if (!IACgetlongparam ('vbar', &barvalue))
  817.         return (false);
  818.         
  819.     return (IACreturnboolean (fastsetbarvalue (barnumber, barvalue)));
  820.     } /*setbarvalueverb*/
  821.     
  822.  
  823. static boolean getbarvalueverb (void) {
  824.     
  825.     /*
  826.     verb that returns the value of one of the bars in the target window.
  827.     */
  828.     
  829.     short barnumber;
  830.     long barvalue;
  831.     
  832.     if (!settargetglobals ()) /*this verb requires an open barchart window*/
  833.         return (false);
  834.         
  835.     if (!IACgetshortparam (keyDirectObject, &barnumber))
  836.         return (false);
  837.         
  838.     barnumber--; /*our IAC interface is 1-based, internally we're 0-based*/
  839.         
  840.     getbarvalue (barnumber, &barvalue);
  841.         
  842.     return (IACreturnlong (barvalue));
  843.     } /*getbarvalueverb*/
  844.     
  845.  
  846. static boolean setbarverb (void) {
  847.     
  848.     /*
  849.     verb that sets both the value and label of one of the bars in the
  850.     target window.
  851.     */
  852.     
  853.     short barnumber;
  854.     bigstring bslabel;
  855.     long barvalue;
  856.     
  857.     if (!settargetglobals ()) /*this verb requires an open barchart window*/
  858.         return (false);
  859.         
  860.     if (!IACgetshortparam (keyDirectObject, &barnumber))
  861.         return (false);
  862.         
  863.     barnumber--; /*our IAC interface is 1-based, internally we're 0-based*/
  864.         
  865.     if (!IACgetstringparam ('lbar', bslabel))
  866.         return (false);
  867.         
  868.     if (!IACgetlongparam ('vbar', &barvalue))
  869.         return (false);
  870.  
  871.     return (IACreturnboolean (setbar (barnumber, bslabel, barvalue)));
  872.     } /*setbarverb*/
  873.     
  874.     
  875. static boolean setbarlabelverb (void) {
  876.     
  877.     /*
  878.     verb that sets the label of one of the bars in the target window.
  879.     */
  880.     
  881.     short barnumber;
  882.     bigstring bslabel;
  883.     
  884.     if (!settargetglobals ()) /*this verb requires an open barchart window*/
  885.         return (false);
  886.         
  887.     if (!IACgetshortparam (keyDirectObject, &barnumber))
  888.         return (false);
  889.         
  890.     barnumber--; /*our IAC interface is 1-based, internally we're 0-based*/
  891.         
  892.     if (!IACgetstringparam ('lbar', bslabel))
  893.         return (false);
  894.         
  895.     return (IACreturnboolean (setbarlabel (barnumber, bslabel)));
  896.     } /*setbarlabelverb*/
  897.     
  898.     
  899. static boolean addbarverb (void) {
  900.     
  901.     /*
  902.     verb that adds a new bar to the target window with indicated label and
  903.     value.
  904.     */
  905.     
  906.     bigstring bslabel;
  907.     long barvalue;
  908.     
  909.     if (!settargetglobals ()) /*this verb requires an open barchart window*/
  910.         return (false);
  911.         
  912.     if (!IACgetstringparam (keyDirectObject, bslabel))
  913.         return (false);
  914.         
  915.     if (!IACgetlongparam ('vbar', &barvalue))
  916.         return (false);
  917.         
  918.     return (IACreturnshort (addbar (bslabel, barvalue) + 1));
  919.     } /*addbarverb*/
  920.     
  921.     
  922. static boolean setbarcountverb (void) {
  923.     
  924.     /*
  925.     changes the number of bars in the target window.
  926.     */
  927.     
  928.     short ctbars;
  929.     
  930.     if (!settargetglobals ()) /*this verb requires an open barchart window*/
  931.         return (false);
  932.         
  933.     if (!IACgetshortparam (keyDirectObject, &ctbars))
  934.         return (false);
  935.         
  936.     return (IACreturnboolean (resetbarchartwindow (ctbars)));
  937.     } /*setbarcountverb*/
  938.     
  939.  
  940. static boolean getbarcountverb (void) {
  941.     
  942.     /*
  943.     returns the number of bars in the target window.
  944.     */
  945.     
  946.     hdlbarchartrecord hb;
  947.     
  948.     if (!settargetglobals ()) /*this verb requires an open barchart window*/
  949.         return (false);
  950.         
  951.     return (IACreturnshort ((**(hdlbarchartrecord) app.appdata).ctbars));
  952.     } /*getbarcountverb*/
  953.     
  954.  
  955. static boolean setunitsverb (void) {
  956.     
  957.     /*
  958.     sets the units string of the target window.  this string is displayed
  959.     with the value of each of the bars.
  960.     */
  961.     
  962.     bigstring bs;
  963.     
  964.     if (!settargetglobals ()) /*this verb requires an open barchart window*/
  965.         return (false);
  966.         
  967.     if (!IACgetstringparam (keyDirectObject, bs))
  968.         return (false);
  969.     
  970.     setbarunits (bs);
  971.         
  972.     return (IACreturnboolean (true));
  973.     } /*setunitsverb*/
  974.     
  975.     
  976. static boolean getbarlabelverb (void) {
  977.     
  978.     /*
  979.     returns the label of one of the bars in the target window.  you provide
  980.     us with a bar number.
  981.     */
  982.     
  983.     short barnumber;
  984.     bigstring barlabel;
  985.     
  986.     if (!settargetglobals ()) /*this verb requires an open barchart window*/
  987.         return (false);
  988.         
  989.     if (!IACgetshortparam (keyDirectObject, &barnumber))
  990.         return (false);
  991.         
  992.     barnumber--; /*our IAC interface is 1-based, internally we're 0-based*/
  993.         
  994.     getbarlabel (barnumber, barlabel);
  995.         
  996.     return (IACreturnstring (barlabel));
  997.     } /*getbarlabelverb*/
  998.     
  999.  
  1000. static boolean bcfastiacmessage (void) {
  1001.     
  1002.     /*
  1003.     it's called when the Applet Toolkit receives a system event aimed at
  1004.     BarChart. these two events can be handled without doing an drawing or
  1005.     window management. for the other side of these messages, look at the
  1006.     system.verbs.apps.BarChart.fast table in Frontier.root.
  1007.     */
  1008.     
  1009.     switch (IACgetverbtoken ()) {
  1010.         
  1011.         case getbarvaluetoken:
  1012.             fastgetbarvalueverb (); break;
  1013.         
  1014.         case setbarvaluetoken:
  1015.             fastsetbarvalueverb (); break;
  1016.         
  1017.         default:
  1018.             IACnothandlederror (); break;
  1019.         } /*switch*/
  1020.         
  1021.     return (false);
  1022.     } /*bcfastiacmessage*/
  1023.     
  1024.     
  1025. static boolean bciacmessage (void) {
  1026.     
  1027.     switch (IACgetverbtoken ()) {
  1028.         
  1029.         case setbarvaluetoken:
  1030.             setbarvalueverb (); break;
  1031.         
  1032.         case getbarvaluetoken:
  1033.             getbarvalueverb (); break;
  1034.             
  1035.         case setbarlabeltoken:
  1036.             setbarlabelverb (); break;
  1037.             
  1038.         case setbartoken:
  1039.             setbarverb (); break;
  1040.             
  1041.         case getbarlabeltoken:
  1042.             getbarlabelverb (); break;
  1043.         
  1044.         case addbartoken:
  1045.             addbarverb (); break;
  1046.             
  1047.         case setunitstoken:
  1048.             setunitsverb (); break;
  1049.                 
  1050.         case setbarcounttoken:
  1051.             setbarcountverb (); break;        
  1052.             
  1053.         case getbarcounttoken:
  1054.             getbarcountverb (); break;    
  1055.             
  1056.         case updatetoken:
  1057.             drawbarchart (); break;
  1058.             
  1059.         default:
  1060.             IACnothandlederror (); break;
  1061.         } /*switch*/
  1062.         
  1063.     return (false);
  1064.     } /*bciacmessage*/
  1065.     
  1066.     
  1067. static boolean bcpack (hpacked) Handle *hpacked; {
  1068.     
  1069.     hdlbarchartrecord hb;
  1070.     
  1071.     if (!copyhandle (app.appdata, hpacked)) 
  1072.         return (false);
  1073.         
  1074.     hb = (hdlbarchartrecord) *hpacked;
  1075.     
  1076.     return (true);
  1077.     } /*bcpack*/
  1078.     
  1079.  
  1080. static boolean bcunpack (hpacked) Handle hpacked; {
  1081.     
  1082.     hdlbarchartrecord hb = (hdlbarchartrecord) hpacked;
  1083.     hdlbarchartrecord hcopy;
  1084.     
  1085.     if ((**hb).versionnumber != 1)
  1086.         return (false);
  1087.         
  1088.     if (!copyhandle ((Handle) hb, (Handle *) &hcopy))
  1089.         return (false);
  1090.         
  1091.     disposehandle (app.appdata);
  1092.     
  1093.     app.appdata = (Handle) hcopy;
  1094.     
  1095.     setchartconsts (); /*reset all computed values*/
  1096.         
  1097.     return (true);
  1098.     } /*bcunpack*/
  1099.     
  1100.     
  1101. static boolean bcgetpicture (hpicture) PicHandle *hpicture; {
  1102.     
  1103.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  1104.     hdlappwindow ha = app.appwindow;
  1105.     Rect r = (**ha).contentrect;
  1106.     
  1107.     *hpicture = nil; /*return value if error*/
  1108.     
  1109.     if (hb == nil) /*no data, it can't be our window*/
  1110.         return (false);
  1111.     
  1112.     *hpicture = OpenPicture (&r);
  1113.     
  1114.     ClipRect (&r);
  1115.     
  1116.     drawbarchart ();
  1117.     
  1118.     ClosePicture ();
  1119.     
  1120.     return (true);
  1121.     } /*bcgetpicture*/
  1122.     
  1123.  
  1124. static boolean bcputpicture (hpicture) PicHandle hpicture; {
  1125.     
  1126.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  1127.     
  1128.     (**hb).backgroundpicture = hpicture;
  1129.     
  1130.     bcupdate ();
  1131.     
  1132.     return (true);
  1133.     } /*bcputpicture*/
  1134.  
  1135.  
  1136. static boolean bcopenprint (void) {
  1137.     
  1138.     app.printinfo.ctpages = 1;
  1139.     
  1140.     return (true);
  1141.     } /*bcopenprint*/
  1142.  
  1143.  
  1144. static boolean bccloseprint (void) {
  1145.     
  1146.     setchartconsts (); /*restore drawing parameters*/
  1147.     } /*bccloseprint*/
  1148.  
  1149.  
  1150. static boolean bcprintpage (pagenumber) short pagenumber; {
  1151.     
  1152.     setchartconsts (); /*reset all the drawing parameters*/
  1153.     
  1154.     drawbarchart ();
  1155.     
  1156.     return (true);
  1157.     } /*bcprintpage*/
  1158.     
  1159.     
  1160. static boolean bchaveselection (void) {
  1161.     
  1162.     return (false); /*no selection in BarChart*/
  1163.     } /*bchaveselection*/
  1164.     
  1165.     
  1166. static boolean bcselectall (void) {
  1167.     
  1168.     return (false); /*no selection in BarChart*/
  1169.     } /*bcselectall*/
  1170.     
  1171.     
  1172. static boolean bcgetcontentsize (void) { /*New in 2.0*/
  1173.     
  1174.     /*
  1175.     called when a BarChart window is zoomed. we return the optimal size
  1176.     for the window. horizontally, it's a function of the number of bars
  1177.     and the width of their labels. vertically, we make it 3/5 of the 
  1178.     window width.
  1179.     */
  1180.  
  1181.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  1182.     hdlappwindow ha = app.appwindow;
  1183.     short i;
  1184.     bigstring bs;
  1185.     short maxwidth = 0;
  1186.     short width;
  1187.     
  1188.     pushlabelstyle ();
  1189.     
  1190.     for (i = 0; i < (**hb).ctbars; i++) {
  1191.         
  1192.         short x = StringWidth ((ConstStr255Param) (**hb).bars [i].label) + 4;
  1193.         
  1194.         maxwidth = max (maxwidth, x);
  1195.         
  1196.         NumToString ((**hb).bars [i].value, bs);
  1197.     
  1198.         pushstring ((**hb).barunits, bs);
  1199.         
  1200.         x = StringWidth (bs) + 4;
  1201.         
  1202.         maxwidth = max (maxwidth, x);
  1203.         } /*for*/
  1204.     
  1205.     width =     
  1206.         ((**hb).vertbaseline * 2) + 
  1207.         
  1208.         (maxwidth * (**hb).ctbars) + 
  1209.         
  1210.         ((**hb).pixelsbetweenbars * ((**hb).ctbars - 1));
  1211.     
  1212.     (**ha).zoomwidth = max (width, minwindowwidth);
  1213.     
  1214.     (**ha).zoomheight = ((**ha).zoomwidth * 3) / 5;
  1215.     
  1216.     return (true);
  1217.     } /*bcgetcontentsize*/
  1218.     
  1219.  
  1220. static boolean bcidle (void) {
  1221.     
  1222.     hdlbarchartrecord hb = (hdlbarchartrecord) app.appdata;
  1223.     short i;
  1224.     
  1225.     setcursortype (cursorisarrow);
  1226.     
  1227.     if (hb == nil) /*no window open*/
  1228.         return (true);
  1229.     
  1230.     for (i = 0; i < (**hb).ctbars; i++) {
  1231.     
  1232.         if ((**hb).bars [i].fldirty) {
  1233.             
  1234.             drawbar (i);
  1235.     
  1236.             drawlabel (i);
  1237.             }
  1238.         
  1239.         (**hb).bars [i].fldirty = false;
  1240.         } /*for*/
  1241.     
  1242.     return (true);
  1243.     } /*bcidle*/
  1244.     
  1245.  
  1246. void main (void) {
  1247.     
  1248.     clearbytes (&app, longsizeof (app)); /*init all fields to 0*/
  1249.     
  1250.     app.creator = 'BARC';
  1251.     
  1252.     app.filetype = 'CHRT';
  1253.     
  1254.     app.usecolor = true;
  1255.     
  1256.     app.resizeable = true;
  1257.     
  1258.     app.eraseonresize = true;
  1259.     
  1260.     app.newrecordcallback = &bcnewrecord;
  1261.     
  1262.     app.disposerecordcallback = &bcdisposerecord;
  1263.     
  1264.     app.idlecallback = &bcadjustcursor;
  1265.     
  1266.     app.activatecallback = (tyappbooleancallback) &bcactivate;
  1267.     
  1268.     app.updatecallback = &bcupdate;
  1269.     
  1270.     app.windowresizecallback = &bcwindowresize;
  1271.     
  1272.     app.iacmessagecallback = &bciacmessage;
  1273.     
  1274.     app.iacfastmessagecallback = &bcfastiacmessage;
  1275.     
  1276.     app.packcallback = &bcpack;
  1277.     
  1278.     app.unpackcallback = &bcunpack;
  1279.     
  1280.     app.getpictcallback = (tyapphandleptrcallback) &bcgetpicture;
  1281.     
  1282.     app.putpictcallback = (tyapphandlecallback) &bcputpicture;
  1283.     
  1284.     app.openprintcallback = &bcopenprint;
  1285.     
  1286.     app.printpagecallback = (tyappshortcallback) &bcprintpage;
  1287.     
  1288.     app.closeprintcallback = &bccloseprint;
  1289.     
  1290.     app.haveselectioncallback = &bchaveselection;
  1291.     
  1292.     app.selectallcallback = &bcselectall;
  1293.     
  1294.     app.idlecallback = &bcidle;
  1295.     
  1296.     app.getcontentsizecallback = &bcgetcontentsize; /*New in 2.0*/
  1297.  
  1298.     runapplet ();
  1299.     } /*main*/
  1300.     
  1301.     
  1302.